﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FinanSoft.Entities;
using FinanSoft.DataLayer;
using FinanSoft.Utilities;

namespace FinanSoft.BusinessLayer
{
    public class StoreRoomManager
    {
        #region Fields
        private bool _IsError;
        private String _ErrorMessage;
        private static StoreRoomManager _instance;
        private List<StoreRoom> _stores;
        #endregion

        #region Propiedades
        public bool IsError
        {
            get
            {
                bool temp = _IsError;
                _IsError = false;
                return temp;
            }
        }

        public String ErrorMessage
        {
            get
            {
                String temp = _ErrorMessage;
                _IsError = false;
                _ErrorMessage = "";
                return temp;
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor privado de la clase para permitir la implementacion del patron singleton
        /// </summary>
        private StoreRoomManager()
        {
            _IsError = false;
            _ErrorMessage = "";
            _stores = StoreRoomDataManager.GetInstance().GetStoreRooms();
            if (_stores == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_STORE_ROOM_READING;
            }
            else
            {
                _IsError = false;
            }

        }
        
        #endregion  

        #region Methods
        /// <summary>
        /// Metodo que obtienen la instancia existente de la clase. Si esta aun no ha sido instanciada, la instancia.
        /// </summary>
        public static StoreRoomManager GetInstance()
        {
            if (_instance == null)
                _instance = new StoreRoomManager();
            return _instance;
        }

        /// <summary>
        /// Crea una nueva bodega con los parametros proporcionados y la inserta en la base de datos
        /// </summary>
        /// <param name="code">Valor alfanumerico ingresado por el usuario como codigo para la nueva bodega</param>
        /// <param name="name">String con el nombre de la nueva bodega</param>
        /// <param name="salesAcc"> Entero con el Id de la cuenta que se usara para el registro de ventas</param>
        /// <param name="purchasesAcc">Entero con el Id de la cuenta que se usara para el registro de compras</param>
        /// <param name="inventoryAcc">Entero con el Id de la cuenta que se usara para el registro de movimientos en el inventario</param>
        /// <param name="salesCostAcc">Entero con el Id de la cuenta que se usara para el registro de movimientos en el costo de ventas</param>
        /// <returns>Valor de verdad correspondiente al exito del registro</returns>
        public bool CreateAndRegisterStorage(string code, string name, int salesAcc, int purchasesAcc, int inventoryAcc, int salesCostAcc)
        {
            StoreRoom newStorage;
            Account sales;
            Account purchases;
            Account inventory;
            Account salesCost;

            sales = CatalogManager.GetInstance().GetAccount(salesAcc);
            purchases = CatalogManager.GetInstance().GetAccount(purchasesAcc);
            inventory = CatalogManager.GetInstance().GetAccount(inventoryAcc);
            salesCost = CatalogManager.GetInstance().GetAccount(salesCostAcc);

            newStorage = new StoreRoom(Constants.INVALID_ID, code, name, sales, purchases, inventory, salesCost);
            return RegisterStorage(newStorage);            
        }

        /// <summary>
        /// Modifica los datos de una bodega existente en la base de datos
        /// </summary>
        /// <param name="id"></param>
        /// <param name="code">Valor alfanumerico ingresado por el usuario como nuevo codigo para la bodega</param>
        /// <param name="name">String con el nuevo nombre de la bodega</param>
        /// <param name="salesAcc"> Entero con el nuevo Id de la cuenta que se usara para el registro de ventas</param>
        /// <param name="purchasesAcc">Entero con el nuevo Id de la cuenta que se usara para el registro de compras</param>
        /// <param name="inventoryAcc">Entero con el nuevo Id de la cuenta que se usara para el registro de movimientos en el inventario</param>
        /// <param name="salesCostAcc">Entero con el nuevo Id de la cuenta que se usara para el registro de movimientos en el costo de ventas</param>
        /// <returns>Valor de verdad correspondiente al exito de la modificacion</returns>
        public bool UpdateStorage(int id, string code, string name, int salesAcc, int purchasesAcc, int inventoryAcc, int salesCostAcc)
        {
            StoreRoom updatedStorage;
            Account sales;
            Account purchases;
            Account inventory;
            Account salesCost;
            bool ErrorDB;
            int counter;

            counter = 0;
            sales = CatalogManager.GetInstance().GetAccount(salesAcc);
            purchases = CatalogManager.GetInstance().GetAccount(purchasesAcc);
            inventory = CatalogManager.GetInstance().GetAccount(inventoryAcc);
            salesCost = CatalogManager.GetInstance().GetAccount(salesCostAcc);

            updatedStorage = new StoreRoom(id, code, name, sales, purchases, inventory, salesCost);

            ErrorDB = StoreRoomDataManager.GetInstance().UpdateStorage(updatedStorage);

            if (!ErrorDB)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_NEW_STORE_ROOM_FAILED;
                return false;
            }

            foreach (StoreRoom old in _stores)
            {
                if (old.Id == updatedStorage.Id)
                {
                    _stores[counter] = updatedStorage;
                    break;
                }

                counter++;
            }

            return true;
        }

        /// <summary>
        /// Metodo que se encarga de registrar una nueva bodega
        /// </summary>
        /// <param name="newStore">Bodega a registrar</param>
        /// <returns>Valor de verdad correspondiente al exito del registro</returns>
        private bool RegisterStorage(StoreRoom newStore)
        {
            int noErrorDB;

            noErrorDB = StoreRoomDataManager.GetInstance().RegisterStorage(newStore);
            if (noErrorDB == -1)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_NEW_STORE_ROOM_FAILED;
                return false;
            }

            newStore.Id = noErrorDB;
            _stores.Add(newStore);
            ItemManager.GetInstance().AddNewStore(newStore);
            return true;
 
        }

        public bool DeleteStorage(int id)
        {
            StoreRoom store = GetStoreRoom(id);
            foreach (Item item in ItemManager.GetInstance().GetItems())
            {
                ItemStoreRoomInfo storeInfo = item.GetStoreRoomInfo(id);
                if (storeInfo.Stock > 0 || storeInfo.Comprometido > 0 || storeInfo.Solicitado > 0)
                {
                    _IsError = true;
                    _ErrorMessage = Constants.ERROR_STORE_NOT_EMPTY;
                    return false;
                }
            }
            if (!StoreRoomDataManager.GetInstance().DeleteStoreRoom(store))
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_STORE_WITH_ENTRIES;
                return false;
            }
            else
            {
                _stores.Remove(store);
                return true;
            }
        }

        /// <summary>
        /// Metodo que retorna la lista de bodegas registradas en el sistema
        /// </summary>
        /// <returns></returns>
        public List<StoreRoom> GetStoreRooms()
        {
            if (_stores == null)
            {
                _IsError = true;
                _ErrorMessage = Constants.ERROR_STORE_ROOM_READING;
            }

            return _stores;
        }

        /// <summary>
        /// Busca una bodega con el Id dado en la lista de bodegas
        /// Si no existe entonces devuelve nulo
        /// </summary>
        /// <param name="id">Id de la bodega que se busca</param>
        /// <returns>Bodega asociada al Id, nulo si no existe</returns>
        public StoreRoom GetStoreRoom(int id)
        {
            foreach (StoreRoom possibleStore in _stores)
            {
                if (possibleStore.Id == id)
                    return possibleStore;
            }
            return null;
        }

        /// <summary>
        /// Busca una bodega con el código en la lista de bodegas
        /// </summary>
        /// <param name="code">Código de la bodega a buscar</param>
        /// <returns>Objeto bodega, si no existe nulo</returns>
        public StoreRoom GetStoreRoom(string code)
        {
            foreach (StoreRoom store in _stores)
            {
                if (store.Code == code)
                    return store;
            }
            return null;
        }

        /// <summary>
        /// Verirfica si un codigo dado ya existe en la lista de bodegas
        /// </summary>
        /// <param name="code"> El codigo del que se desea verificar su existencia</param>
        /// <returns>Un valor de verdad correspondiente a la existencia del objeto</returns>
        public bool CheckCode(string code)
        {
            foreach (StoreRoom store in _stores)
            {
                if (store.Code == code)
                    return true;
            }

            return false; 
        }


        /// <summary>
        /// Método que se encarga de obtener la bodega de mayor stock para un 
        /// artículo en específico
        /// </summary>
        /// <param name="item">Artículo</param>
        /// <returns>Objeto bodega con mayor stock</returns>
        public StoreRoom GetDefaultStoreRoom(Item item)
        {
            if (item != null)
            {
                int max = 0;
                StoreRoom storeMax = null;

                foreach (ItemStoreRoomInfo storeInfo in item.StoreInfo)
                {
                    if (storeInfo.Stock > max)
                    {
                        max = storeInfo.Stock;
                        storeMax = storeInfo.StoreRoom;
                    }
                }

                return storeMax;
            }
            return null;
        }

        #endregion        
    }
}
